/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tp2;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/******************************************************************************
 *******************************Jeu********************************************
 ******************************************************************************/
/*
 * Cette classe crée le panneau de jeu et permet de valider tous les mouvements
 * possibles fait par les pions selon le joueur actuel. De plus, elle fourni
 * les données telles que le nombre de pions de chaque joueur et aussi le joueur
 * qui doit jouer
 */
public class Jeu extends JPanel implements Serializable {

    private Fenetre fenetre;
    private Damier pnlDamier;
    private JPanel pnlInfo = new JPanel();
    private JLabel lblJoueurActuTexte, lblJoueurActu, lblNbPion1Texte, lblNbPion2Texte,
            lblNbPion3Texte, lblNbPion4Texte, lblNbPion1, lblNbPion2, lblNbPion3, lblNbPion4;
    private JButton btnAbandonner, btnSuperRed;
    private int nbJoueurs = 2;
    private String nomJoueur1 = "Joueur 1";
    private String nomJoueur2 = "Joueur 2";
    private String nomJoueur3 = "Joueur 3";
    private String nomJoueur4 = "Joueur 4";

    private boolean[] listeMorts; // Liste des joueurs morts
    private boolean[] listeSuperRedd; // Liste des joueurs ayant utilise leurs superredd
    private int joueurActu = 1; // Joueur actuel
    private Cases CaseSelect = null; // Case selectionne actuellement
    private boolean nextPionRedd = false; // Indique si le prochain pion sera un super redd
    private boolean victoire = false; // Indique s'il y a eu victoire

    /**
     * On veut des points
     */
    public static enum Joueur {
        JOUEUR1,
        JOUEUR2
    };

    /**
     * Notre constructeur
     * @param fenetre Référence vers le JFrame principal
     */
    public Jeu(Fenetre fenetre) {
        this.fenetre = fenetre;

        this.setLayout(new BorderLayout());

        this.initComposants();
        this.initPanneaux();
        this.initJeu();

        update();
    }

    /**
     * On initialise les composants
     */
    private void initComposants() {
        pnlDamier = new Damier(this);
        lblJoueurActu = new JLabel("1");
        lblJoueurActuTexte = new JLabel("Tour du joueur : ");
        lblNbPion1 = new JLabel("0");
        lblNbPion1Texte = new JLabel();
        lblNbPion2 = new JLabel("0");
        lblNbPion2Texte = new JLabel();
        lblNbPion3 = new JLabel("0");
        lblNbPion3Texte = new JLabel();
        lblNbPion4 = new JLabel("0");
        lblNbPion4Texte = new JLabel();
        btnAbandonner = new JButton("Abandonner la partie");
        btnSuperRed = new JButton("Activer le pouvoir SUPER RED");
        btnSuperRed.setEnabled(false);
    }

    /**
     * On initialise les panneaux et leur contenu
     */
    private void initPanneaux() {
        JPanel pnlSecondaire1 = new JPanel();
        JPanel pnlSecondaire2 = new JPanel();
        JPanel pnlSecondaire3 = new JPanel();
        JPanel pnlSecondaire4 = new JPanel();
        JPanel pnlSecondaire5 = new JPanel();

        lblJoueurActu.setOpaque(true);

        pnlSecondaire1.add(lblJoueurActuTexte);
        pnlSecondaire1.add(lblJoueurActu);
        pnlSecondaire2.add(lblNbPion1Texte);
        pnlSecondaire2.add(lblNbPion1);
        pnlSecondaire3.add(lblNbPion2Texte);
        pnlSecondaire3.add(lblNbPion2);
        pnlSecondaire4.add(lblNbPion3Texte);
        pnlSecondaire4.add(lblNbPion3);
        pnlSecondaire5.add(lblNbPion4Texte);
        pnlSecondaire5.add(lblNbPion4);

        pnlInfo.setLayout(new GridLayout(7, 1));
        pnlInfo.add(pnlSecondaire1);
        pnlInfo.add(pnlSecondaire2);
        pnlInfo.add(pnlSecondaire3);
        pnlInfo.add(pnlSecondaire4);
        pnlInfo.add(pnlSecondaire5);
        pnlInfo.add(btnSuperRed);
        pnlInfo.add(btnAbandonner);
        btnSuperRed.addActionListener(new GererEvenement());
        btnAbandonner.addActionListener(new GererEvenement());
        this.add(pnlDamier);
        this.add(pnlInfo, BorderLayout.EAST);

    }

    /**
     * Permet de sélectionner et déselectionner une case
     * @param caseSelect La case a selectionner
     */
    public void toggleCaseSelect(Cases caseSelect) {
        if (isCaseSelect()) {
            this.CaseSelect = null;
        } else {
            this.CaseSelect = caseSelect;
        }
    }

    /**
     * Permet de savoir si le prochain pion sera un SuperRedd
     * @return Si le prochain pion doit être un superredd
     */
    public boolean isNextPionRedd() {
        return nextPionRedd;
    }

    /**
     * Permet de setter l'état du prochain pion (SuperRedd ou non)
     * @param nextPionRedd Si true 
     */
    public void setNextPionRedd(boolean nextPionRedd) {
        this.nextPionRedd = nextPionRedd;
    }

    /**
     * Permet d'obtenir le bouton superRedd
     * @return Le bouton super redd
     */
    public JButton getBtnSuperRed() {
        return btnSuperRed;
    }

    /**
     * Permet de savoir si une case est sélectionné ou non
     * @return true | false Si la case est sélectionnée
     */
    public boolean isCaseSelect() {
        return (this.CaseSelect != null);
    }

    /**
     * Permet d'obtenir la case actuellement sélectionnée
     * @return La case sélectionnée
     */
    public Cases getCaseSelect() {
        return CaseSelect;
    }

    /**
     * Permet d'obtenir la case à partir des coordonnée x, y
     * @param x La position en x
     * @param y La position en y
     * @return La case selon la position
     */
    public Cases getCase(int x, int y) {
        return this.pnlDamier.getCases(x, y);
    }

    /**
     * Permet d'obtenir le joueur actuel
     * @return La no. du joueur actuel
     */
    public int getJoueurActu() {
        return this.joueurActu;
    }

    /**
     * Indique si le joueur actuel a utilisé sont superRedd
     */
    public void setSuperReddUsed() {
        listeSuperRedd[joueurActu - 1] = true;
    }

    /**
     * Permet de savoir si le SuperRedd
     * @return Si le superRedd est utilisé
     */
    public boolean isSuperReddUsed() {
        return listeSuperRedd[joueurActu - 1];
    }

    /**
     * Réinitialise le jeu pour une nouvelle partie
     */
    public void initJeu() {
        clearGame(); // On initialise le damier

        // Initialisation de différente variables
        nbJoueurs = Options.getNbJoueurs(); // On change le nombre de nouvelle
        this.victoire = false;
        listeMorts = new boolean[nbJoueurs];
        listeSuperRedd = new boolean[nbJoueurs];
        joueurActu = 1;

        // On ajoute les pions selon le nombre de joueur
        switch (nbJoueurs) {
            case 2:
                getCase(1, 1).initCaseJoueur(1);
                getCase(8, 8).initCaseJoueur(1);
                getCase(1, 8).initCaseJoueur(2);
                getCase(8, 1).initCaseJoueur(2);
                break;
            case 3:
                getCase(1, 1).initCaseJoueur(1);
                getCase(8, 8).initCaseJoueur(2);
                getCase(8, 1).initCaseJoueur(3);
                break;
            case 4:
                getCase(1, 1).initCaseJoueur(1);
                getCase(8, 8).initCaseJoueur(2);
                getCase(1, 8).initCaseJoueur(3);
                getCase(8, 1).initCaseJoueur(4);
                break;
            default:
                System.out.println("fail");
                break;
        }

        update(); // Mise à jour de l'affichage
    }

    /**
     * Supprime tous les pions du jeu et les remets sous un proprio de 0 et pas SuperRedd
     */
    public void clearGame() {
        for (Component i : this.pnlDamier.getComponents()) {
            ((Cases) i).getPion().clear();
        }
    }

    /**
     * Permet d'obternir le nombre de pion de chaque joueur
     * @return Array contenant autant de case que de joueur et chaque case contient le nombre de pion
     */
    public int[] getNbPions() {
        int[] nbPion = new int[nbJoueurs];

        for (Component i : this.pnlDamier.getComponents()) {
            int proprio = ((Cases) i).getPion().getProprio();
            if (proprio <= nbJoueurs && proprio != 0 && ((Cases) i).getPion().isVisible()) {
                nbPion[proprio - 1]++;
            }
        }
        return nbPion;
    }

    /**
     * Mise à jour des noms des joueurs
     */
    public void updateNomJoueur() {
        nomJoueur1 = Options.getNomJoueur1();
        nomJoueur2 = Options.getNomJoueur2();
        nomJoueur3 = Options.getNomJoueur3();
        nomJoueur4 = Options.getNomJoueur4();
        lblNbPion1Texte.setText("<html>Nb pions <strong>" + nomJoueur1 + "</strong> : </html>");
        lblNbPion2Texte.setText("<html>Nb pions <strong>" + nomJoueur2 + "</strong> : </html>");
        lblNbPion3Texte.setText("<html>Nb pions <strong>" + nomJoueur3 + "</strong> : </html>");
        lblNbPion4Texte.setText("<html>Nb pions <strong>" + nomJoueur4 + "</strong> : </html>");
    }

    /**
     * Mise à jour de l'affichage des noms en fonction du nombre de joueur
     */
    public void updateNbJoueur() {
        if (nbJoueurs == 2) {
            lblNbPion3Texte.setVisible(false);
            lblNbPion4Texte.setVisible(false);
            lblNbPion3.setVisible(false);
            lblNbPion4.setVisible(false);
        } else if (Options.getNbJoueurs() == 3) {
            lblNbPion3Texte.setVisible(true);
            lblNbPion3.setVisible(true);
            lblNbPion4Texte.setVisible(false);
            lblNbPion4.setVisible(false);
        } else {
            lblNbPion3Texte.setVisible(true);
            lblNbPion3.setVisible(true);
            lblNbPion4Texte.setVisible(true);
            lblNbPion4.setVisible(true);
        }
        btnSuperRed.setEnabled(isCaseSelect());
    }

    /**
     * Mise à jour de l'affichage du nombre de pion
     */
    public void updateNbPions() {
        int[] nbPion = this.getNbPions();
        lblNbPion1.setText(nbPion[0] + "");
        lblNbPion2.setText(nbPion[1] + "");
        if (nbJoueurs == 4 || nbJoueurs == 3) {
            lblNbPion3.setText(nbPion[2] + "");
        }
        if (nbJoueurs == 4) {
            lblNbPion4.setText(nbPion[3] + "");
        }
    }

    /**
     * Mise à jour de la couleur du background du joueur actuel
     */
    public void updateCouleur() {
        switch (joueurActu) {
            case 1:
                lblJoueurActu.setForeground(Color.lightGray);
                lblJoueurActu.setBackground(Color.blue);
                break;
            case 2:
                lblJoueurActu.setForeground(Color.lightGray);
                lblJoueurActu.setBackground(Color.white);
                break;
            case 3:
                lblJoueurActu.setForeground(Color.lightGray);
                lblJoueurActu.setBackground(Color.red);
                break;
            case 4:
                lblJoueurActu.setForeground(Color.lightGray);
                lblJoueurActu.setBackground(Color.black);
                break;
        }
        lblJoueurActu.setText("     " + Options.getNomJoueur(joueurActu) + "     ");
    }

    /**
     * Permet de savoir combien de joueur sont encore vivant
     * @return Le nombre de joueur vivant
     */
    public int getJoueurVivant() {
        int restant = 0;
        for (int i = 0; i < listeMorts.length; i++) {
            if (!listeMorts[i]) {
                restant++;
            }
        }
        return restant;
    }

    /**
     * Mise à jour de l'affichage
     */
    public void update() {

        updateNomJoueur();
        updateNbJoueur();
        updateNbPions();
        updateCouleur();

        if (isSuperReddUsed()) {
            btnSuperRed.setEnabled(false);
        }
        
        valideVictoire();
        sequenceVictoire();
    }

    /**
     * Lance la séquence de la victoire si jamais il reste seulement un ou moins joueur vivant
     */
    public void sequenceVictoire() {
        if (!this.victoire && getJoueurVivant() <= 1) {
            this.victoire = true;
            int joueurVictoire = 0;
            for (int i = 0; i < listeMorts.length; i++) {
                if (!listeMorts[i]) {
                    joueurVictoire = i + 1;
                }
            }
            if(joueurVictoire > 0)
                Fenetre.incrementStat(joueurVictoire);

            JOptionPane.showMessageDialog(null, Options.getNomJoueur(joueurVictoire) + " a gagne");
            fenetre.initPnlMenu();
        }
    }

    /**
     * Permet de simplement tué le joueur passer en paramètre
     * @param i Le numéro du joueur à tué
     */
    private void tue(int i) {
        listeMorts[i-1] = true;
        JOptionPane.showMessageDialog(null, Options.getNomJoueur(i) + " est vraiment nul");
    }

    /**
     * Vérifie les victoires et tue un joueur si celui-ci peut mourir
     */
    public void valideVictoire() {
        int[] nbPion = this.getNbPions();

        for (int i = 0; i < nbPion.length; i++) {
            if ((nbPion[i] == 0 && !listeMorts[i])) {
                tue(i+1);
            }

            if((!isMouvementPossible(i + 1)) && !listeMorts[i]) {
                int max = 0;
                int pmax = 0;
                for(int k = 0; k < nbPion.length; k++) {
                    max = Math.max(max, nbPion[k]);
                    if(max == nbPion[k]) {
                        pmax = k;
                    }
               }
                if(pmax == i) {
                    for(int k = 0; k < nbPion.length; k++) {
                        if(pmax == k) {
                            listeMorts[k] = false;
                        } else {
                            listeMorts[k] = true;
                        }
                   }
                } else {
                    tue(i+1);
                }

            }
        }

    }

    /**
     * Permet de passe au prochain joueur
     */
    public void finiTour() {
        update();

        for (Component i : this.pnlDamier.getComponents()) {
            ((Cases) i).unSelect();
        }
        this.CaseSelect = null;

        if (joueurActu == nbJoueurs) {
            joueurActu = 1;
        } else {
            joueurActu++;
        }

        if (listeMorts[joueurActu - 1]) {
            update();
            finiTour();
            return;
        }

        lblJoueurActu.setText("" + joueurActu);
        
        update();
    }

    /**
     * Permet de savoir si il y a encore un mouvement de possible pour le joueur en paramètre
     * @param joueur Le joueur à tester
     * @return Si il y a un mouvement possible pour le joueur actuel
     */
    public boolean isMouvementPossible(int joueur) {
        for (Component z : this.pnlDamier.getComponents()) {
            Cases caseI = ((Cases) z);
            if (joueur == caseI.getPion().getProprio() && caseI.getPion().isVisible()) {
                int[] posThis = caseI.getPos();
                for (int i = (posThis[0] - 2); i <= (posThis[0] + 2); i++) {
                    for (int j = (posThis[1] - 2); j <= (posThis[1] + 2); j++) {
                        if (!(i == posThis[0] && j == posThis[1]) && i >= 1 && j >= 1 && i <= 8 && j <= 8) {
                            if (!this.getCase(i, j).getPion().isVisible()) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * Permet de savoir si il y a un mouvement possible pour le joueur actuel
     * @return Si il y a un mouvement possible pour le joueur actuel
     */
    public boolean isMouvementPossible() {
        return isMouvementPossible(getJoueurActu());
    }

    /**
     * Gestion des évènement
     */
    class GererEvenement implements ActionListener, Serializable {

        public void actionPerformed(ActionEvent ae) {
            /**
             * Click sur le bouton SuperRedd
             */
            if (ae.getSource() == btnSuperRed) {
                btnSuperRed.setEnabled(false);
                setNextPionRedd(true);


            } else if (ae.getSource() == btnAbandonner) { // Abandon de la partie
                int option = JOptionPane.showConfirmDialog(null, "Êtes-vous sur de vouloir abandonner"
                        + " le champs de bataille Soldat ?", "Demande d'abandon",
                        JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                if (option == JOptionPane.YES_OPTION) {
                    tue(joueurActu); // On tue le joueur
                    finiTour(); // Et on passe au prochain joueur

                } else {
                    JOptionPane.showMessageDialog(null, "Retournez au combat ! ");

                }
            }
        }
    }
}
